iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
自我挑戰組

玩轉 React 從0到1系列 第 21

【Day 21】React 關於 Hook

  • 分享至 

  • xImage
  •  

前言

React hook 是 React V16.8 新增的功能,它改變了 React 寫 Class Component 的習慣,轉而改成寫 Functional Component,早期的 React 元件事實上就區分為 Class 跟 Functional兩種,但是 Class 通常是可以控制 State 跟 生命週期的而 Functional 主要是用來呈現 UI 的部分,而 Hook 打破這層限制,統一使用 Functional Component,直接在內部就可以管理 State。

其實 Hook 很像 JS 的 Module Pattern,Module Pattern 是 JS 利用函數閉包(Closure)的特性,藉由閉包實現封裝的功能,將變數和方法限制在範圍內使用,達到避免(變數、功能)全局污染的一種方法。

Module Pattern (模組模式)

因為 Javascript 原生並沒有 private, public, protected 的概念,而是依靠作用域,所以要切分開來只能依靠閉包。(不清楚可以看:【Day 6】關於ES6作用域)

閉包(Closure):閉包是指變數的生命週期只存在在該 function 中,如果離開了 function,變數會自動被回收而且不可在使用,而且必須要事先在 function 中宣告。

Module Pattern: 就是利用閉包的特性,將變數和函數限制在特定範圍內使用

舉例來說:

var exampleModule = (function(){
  var counter = 0;
  return {
    increase: function() {
      return counter += 1;
    },
    decrease: function() {
      return counter -= 1;
    }
  }
}());
console.log(exampleModule.increase()); // 1
console.log(exampleModule.decrease()); // 0

從 React 到 React Hook

原始寫法:

import React, { Component } from 'react';

class Example extends Component {
    constructor(props) {
        super(props);
        this.state = { count:0 }
        this.increase = this.increase.bind(this);
    }
    increase(){
        this.setState({count:this.state.count+1})
    }
    render() { 
        return (
            <div>
                <p>你已經點了 {this.state.count} 次</p>
                <button onClick={this.increase}>點我</button>
            </div>
        );
    }
}
export default Example;

React Hook 寫法:

import React, { useState } from 'react';
function Example(){
    const [ count , setCount ] = useState(0);
    return (
        <div>
            <p>你已經點了 {count} 次</p>
            <button onClick={()=>{setCount(count+1)}}>點我</button>
        </div>
    )
}
export default Example;

這裡要注意,要使用 React Hook 並不需要另外安裝套件,而是 React 16.8 以上的內建功能。

React Hook 優點

較接近原生的 js 寫法,對於剛開始接觸的人有好處,且不需要懂 ES6 也可以寫
減少了解太過多餘的元件週期,只要控制好 useEffect 即可
用相對簡單的寫法解決複雜的問題,這點尤其重要

1.元件更好重複利用

  • 每次調用 Hook 的 Component,都會另外生成一份 Component 獨立的 State
  • UseState 和 UseEffect 雖然依賴於元件,但是可以在元件外部去做定義

2.程式碼更簡潔

  • useState 可以直接讀取並且寫入 state,與原先需要 setState()的方法不同
  • useEffect 取代了 componentDidUpdate, componentDidMount, componentWillUnMount 生命週期的邏輯

React Hook 缺點

狀態不同步

當下面這段程式運行的時候,可以試著先點擊“3 秒後跳出值”的按鈕,在去點擊“增加”的按鈕,就會發現最後Alert 的數字是當時“點擊3 秒後跳出值”的當前數值,而不是最後的增加後的數值。這是因為異步操作時,所引用的變量是之前的(作用域與閉包概念),但是這問題在 Class Component 就不會發生,因為 Class Component 的屬性都放在一個 instance 上,並且使用 this.state.xxx 和 this.method() 進行調用,而每次都是在同一個 instance 上取值,所以沒有所謂之前的值的問題。

import React, { useState } from "react";
const Example = () => {
  const [counter, setCounter] = useState(0);
  const onAlertButtonClick = () => {
    setTimeout(() => {
      alert("最後顯示值: " + counter);
    }, 3000);
  };
  return (
    <div>
      <p>你已經點了 {counter} 次</p>
      <button onClick={() => setCounter(counter + 1)}>增加</button>
      <button onClick={onAlertButtonClick}>
        3 秒後跳出值
      </button>
    </div>
  );
};

export default Example;

結論

  • 介紹了 React Hook 優缺點
  • 介紹了 Module Pattern

/images/emoticon/emoticon11.gif


上一篇
【Day 20】React 結合 Redux 與 React-Router
下一篇
【Day 22】React 關於 Hook (2)
系列文
玩轉 React 從0到130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言